# add_traces.pl (C) Marko Kivij?rvi 2006
# Dummy checks
die "Specify an input file!\n" if $ARGV[0] eq "";
die "Specify an output file!\n" if $ARGV[1] eq "";
die "File not found!\n" unless -e $ARGV[0];
die "Incorrect file extension for a C/C++ file!\n" 
                if ( $ARGV[0] !~ /(.*)\.(c|cpp)$/ );
 
# Constants
my $INC_TRACER_H = "#include \"TTracer.h\"\n";
my $TRACERVAR = "TRACER";
 
# Parse output filename from the input filename
my $file = $ARGV[0];
my $origFile = $ARGV[1];
$file =~ s/\//\\/g;
$origFile =~ s/\//\\/g;
print("file:$file,origFile:$origFile\n");
system( "copy /V /Y  $file, $origFile" );
 
# Reset the input record separator (newline) so the entire file is read at once
undef $/;
 
# Read the input file
$_ = <>; # All there
 
# Adds a tracer macro after each function definition
s/
    ((\b\w*?\b[&*]?)?            # Possible function return type
    \s+                         # One or more empty spaces
    (\b\w+?\b)                  # Class name
    \s*?                        # Possible empty space
    ::                          # ::
    \s*?                        # Possible empty space
    (~?\b\w+?\b)                # Function name
    \s*?                        # Possible empty space
    \(                          # Opening brace
    ([^)]*?)                    # Possible function parameters
    \)                          # Closing brace
    \s*                        # Possible empty space
    (const)?                    # Possible 'const'
    [^{;\/]*?                  # Possible empty space or constructor
                                # initializer list
    \{)                         # Opening curly brace
	(\s*)
	($TRACERVAR\(\"(\b\w*?\b[&*]?)? \s*(\b\w+?\b)::(~?\b\w+?\b)\(([^)]*?)\)\s*(const)? \"\))?
/
    Parse($&,$1,$2,$3,$4,$5,$6,$7,$8)    # Print the match and add the macro
/gxe; # g = repeat, x = split regex to multiple lines, e = evaluate substitution
 
open OUT, ">$file" or die "Cannot open file $file $!\n";
$pos = index($_, $INC_TRACER_H);
if($pos < 0){
	print OUT $INC_TRACER_H;
}
print OUT;
close OUT;
 
exit 0;
 
sub Parse {
    my $match   = shift;
	my $wholefunc = shift;
    my $ret     = shift;
    my $class   = shift;
    my $func    = shift;
    my $param   = shift;
    my $const   = shift;
	my $space = shift;
	my $tracer = shift;

    foreach ($ret, $class, $func, $param ) {
        s/\s{2,}/ /g;
        s/\n//g;
    }
	
	my $tracerfunc = "";
	$tracerfunc .= $ret." " if defined $ret;
    $tracerfunc .= $class."::".$func."(";
    $tracerfunc .= $param if $param ne "";
    $tracerfunc .= ")";
    $tracerfunc .= " ".$const if defined $const;
	my $output_tracer .= $TRACERVAR."(\"".$tracerfunc."\")";

    my $debug = $match;
	if(not defined $tracer){       #no TRACER macro
	$debug=~s/\s*$//;
    $debug.="\n    ".$output_tracer.$space;
	}else{
		if($tracer ne $output_tracer){ # TRACER macro is out of date
			$debug = $wholefunc;
			$debug .= "\n    ".$output_tracer;
		}
	}
 
    return $debug;
}